package com.github.cakin.shiro.chapter23.client;

import com.github.cakin.shiro.chapter23.core.ClientSavedRequest;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticationFilter;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

/**
 * @className: ClientAuthenticationFilter
 * @description: 实现身份认证的拦截器
 * @date: 2020/6/2
 * @author: cakin
 */
public class ClientAuthenticationFilter extends AuthenticationFilter {
    /**
     * 80端口
     */
    private static final int PORT80 = 80;
    /**
     * 443端口
     */
    private static final int PORT443 = 443;

    /**
     * 功能描述：判断身份是否已经认证了
     *
     * @param request     请求
     * @param response    响应
     * @param mappedValue mappedValue
     * @return boolean 是否已认证
     * @author cakin
     * @date 2020/6/2
     */
    @Override
    protected boolean isAccessAllowed( ServletRequest request, ServletResponse response, Object mappedValue ) {
        Subject subject = getSubject(request, response);
        // 如果没有认证，走onAccessDenied
        return subject.isAuthenticated();
    }

    /**
     * 功能描述：认证流程
     *
     * @param request  请求
     * @param response 响应
     * @return boolean false
     * @throws Exception
     * @author cakin
     * @date 2020/6/2
     */
    @Override
    protected boolean onAccessDenied( ServletRequest request, ServletResponse response ) throws Exception {
        // 首先得到请求参数 backUrl，即登录成功重定向到的地址
        String backUrl = request.getParameter("backUrl");
        // 保存请求到会话
        saveRequest(request, backUrl, getDefaultBackUrl(WebUtils.toHttp(request)));
        // 重定向到登录地址（server 模块）
        redirectToLogin(request, response);
        return false;
    }

    /**
     * 功能描述：保存请求到会话
     *
     * @param request     请求
     * @param backUrl     backUrl
     * @param fallbackUrl fallbackUrl
     * @author cakin
     * @date 2020/6/2
     */
    protected void saveRequest( ServletRequest request, String backUrl, String fallbackUrl ) {
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        // session中保存fallbackUrl
        session.setAttribute("authc.fallbackUrl", fallbackUrl);
        HttpServletRequest httpRequest = WebUtils.toHttp(request);
        SavedRequest savedRequest = new ClientSavedRequest(httpRequest, backUrl);
        // session中保存 ClientSavedRequest
        session.setAttribute(WebUtils.SAVED_REQUEST_KEY, savedRequest);
    }

    /**
     * 功能描述：获取 DefaultBackUrl
     *
     * @param request 请求
     * @return String DefaultBackUrl
     * @author cakin
     * @date 2020/6/2
     */
    private String getDefaultBackUrl( HttpServletRequest request ) {
        String scheme = request.getScheme();
        String domain = request.getServerName();
        int port = request.getServerPort();
        String contextPath = request.getContextPath();
        // 拼接成类型 http://localhost:80
        StringBuilder backUrl = new StringBuilder(scheme);
        backUrl.append("://");
        backUrl.append(domain);
        if ("http".equalsIgnoreCase(scheme) && port != PORT80) {
            backUrl.append(":").append(String.valueOf(port));
        } else if ("https".equalsIgnoreCase(scheme) && port != PORT443) {
            backUrl.append(":").append(String.valueOf(port));
        }
        // 拼接contextPath
        backUrl.append(contextPath);
        // 拼接backUrl
        backUrl.append(getSuccessUrl());
        return backUrl.toString();
    }
}
